//
//  HttpRequest_Curl.cpp
//  EZC_Library
//
//  Created by ellzu on 14-9-23.
//  Copyright (c) 2014年 ellzu. All rights reserved.
//

#include "HttpRequest_Curl.h"
#include "HttpRequest.h"
#include "EZLog/EZLog.h"

using namespace EZHttp;

HttpRequest_CURL::HttpRequest_CURL()
{
    static int isInitGlobal = 0;
    if (isInitGlobal==0) {
        isInitGlobal = 1;
        curl_global_init(true);
    }
    
    
}
HttpRequest_CURL::~HttpRequest_CURL()
{
}
//void HttpRequest_CURL::setUrl(const std::string &url)
//{
//    curl_easy_setopt(_curl, CURLOPT_URL,url.c_str());
//}
//void HttpRequest_CURL::setMethod(const std::string &method)
//{
//    if (method.compare("GET")==0) {
//        curl_easy_setopt(_curl, CURLOPT_PUT,0L);
//        curl_easy_setopt(_curl, CURLOPT_POST,0L);
//        curl_easy_setopt(_curl,CURLOPT_HTTPGET, 1L);
//        
//    }else if(method.compare("PUT")==0){
//        curl_easy_setopt(_curl, CURLOPT_POST,0L);
//        curl_easy_setopt(_curl,CURLOPT_HTTPGET, 0L);
//        curl_easy_setopt(_curl, CURLOPT_PUT,1L);
//        
//    }else{ //POST
//        curl_easy_setopt(_curl,CURLOPT_HTTPGET, 0L);
//        curl_easy_setopt(_curl, CURLOPT_PUT,0L);
//        curl_easy_setopt(_curl, CURLOPT_POST,1L);
//    }
//}

//void HttpRequest_CURL::setRequestValue(const std::string &key,const std::string &value)
//{
//}
//void HttpRequest_CURL::setHeader(const std::string &key,const std::string &value)
//{
//    
//}

void HttpRequest_CURL::startSync()
{
    _curl = curl_easy_init();
    curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L);
    
    setupOption();
    
    CURLcode code = curl_easy_perform(_curl);

    if (code==CURLE_OK) {
        this->onHttpRequestSuccess();
    }else{
        this->onHttpRequestFail();
    }
    
    curl_easy_cleanup(_curl);
    _curl = 0;
}
void HttpRequest_CURL::startAsync()
{
}

void HttpRequest_CURL::setupOption()
{
    HttpRequest *request = this->_ownRequest;
    std::string url = request->url();
    
    
    std::string postValue = this->postValueToString();
    
    std::string method = request->method();
    if (method.compare("GET")==0) {
//        curl_easy_setopt(_curl, CURLOPT_PUT,0L);
//        curl_easy_setopt(_curl, CURLOPT_POST,0L);
        curl_easy_setopt(_curl,CURLOPT_HTTPGET, 1L);
        if (postValue.length() > 0) {
            url.append("?"+postValue);
        }
    }else if(method.compare("PUT")==0){
//        curl_easy_setopt(_curl, CURLOPT_POST,0L);
//        curl_easy_setopt(_curl,CURLOPT_HTTPGET, 0L);
        curl_easy_setopt(_curl, CURLOPT_PUT,1L);
        
    }else{ //POST
//        curl_easy_setopt(_curl,CURLOPT_HTTPGET, 0L);
//        curl_easy_setopt(_curl, CURLOPT_PUT,0L);
        curl_easy_setopt(_curl, CURLOPT_POST,1L);
        curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, postValue.c_str());
        curl_easy_setopt(_curl,CURLOPT_POSTFIELDSIZE,postValue.length());
    }
    curl_easy_setopt(_curl, CURLOPT_URL,url.c_str());
//    CURLOPT_VERBOSE
    curl_easy_setopt(_curl, CURLOPT_VERBOSE, 0);//设置为非0在执行时打印请求信息
    
    curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1);//设置为非0，响应头信息Location
    
    //设置对应的COOKIEFILE路径，该路径文件并不一定需要在物理磁盘上实际存在
    curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, "/temp/ezhttprequest.cookie");
    
    curl_easy_setopt(_curl, CURLOPT_HEADER, 0);//设置为非0将响应头信息同响应体一起传给WRITEFUNCTION
    
    curl_easy_setopt(_curl, CURLOPT_HEADERFUNCTION,s_header_callback);
    curl_easy_setopt(_curl, CURLOPT_HEADERDATA,this);
    
    curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, 1L); // 0 打开进度 1 关闭进度
    curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION,s_progress_callback);
    curl_easy_setopt(_curl, CURLOPT_PROGRESSDATA,this);
    
    curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, s_write_data);
    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, this);
    
}
std::string HttpRequest_CURL::postValueToString()
{
//    struct curl_httppost *formpost=NULL;
//    struct curl_httppost *lastptr=NULL;
//    curl_formadd(&formpost,&lastptr,CURLFORM_COPYNAME, "sendfile",CURLFORM_FILE, "postit2.c",CURLFORM_END);
    
//    CURLOPT_POSTFIELDS
//    curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, "email=myemail@163.com&password=mypassword");
//    curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,strlen(postfields));
    
    std::string postValue;
    
    std::map<std::string,std::string> *requestValues = this->requestValues();
    std::map<std::string,std::string>::iterator it = requestValues->begin();
    while (it!=requestValues->end()) {
        
        std::string key = it->first;
        std::string value = it->second;
        if (key.length()>0 && value.length()>0) {
            if (postValue.length()>0) {
                postValue.append("&");
            }
            postValue.append(key+"="+value);
        }
        
        it++;
    }
    return postValue;
}

size_t HttpRequest_CURL::s_header_callback(char *buffer,   size_t size,   size_t nitems,   void *userdata)
{
    HttpRequest_CURL *cthis = (HttpRequest_CURL*)userdata;
    return cthis->header_callback(buffer, size, nitems);
}
size_t HttpRequest_CURL::header_callback(char *buffer,   size_t size,   size_t nitems)
{
//    EZLOG_DEBUG_GUESSLEN("HttpRequest_CURL", 1024, "header_callback::%s",buffer);
    std::string sbuffer(buffer);
    if (sbuffer.length() != size*nitems) {
        sbuffer.clear();
        sbuffer.append(buffer, size*nitems);
    }
    std::string endStr("\r\n");
    if (size*nitems==endStr.length() && endStr.compare(sbuffer)==0 ) {
        double len = 0;
        curl_easy_getinfo(_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD,&len);
//        this->_ownRequest->response()->setContentLen((size_t)len);
        this->response_setContentLen(len);

        this->onHttpRequestResponseHeader();
        
    }else{
        this->_ownRequest->response()->headers()->push_back(sbuffer);
    }
    
    return size*nitems;
}

size_t HttpRequest_CURL::s_write_data(char *buffer, size_t size, size_t nitems, void *outstream)
{

    HttpRequest_CURL *cthis = (HttpRequest_CURL*)outstream;
    return cthis->write_data(buffer,size, nitems);
}

size_t HttpRequest_CURL::write_data(char *buffer,size_t size, size_t nitems)
{
    return this->onHttpRequestReciveContent((unsigned char*)buffer, size*nitems);
    
//    
//    size_t writeSize = this->onHttpRequestReciveContent((unsigned char*)buffer, size*nitems);
////    this->_ownRequest->response()->appendBuffer(buffer, size*nitems);
//    if (writeSize==0) {
//        this->response_AppendBuffer((unsigned char*)buffer, size*nitems);
//    }
//    
//    this->onHttpRequestProgress();
////    EZLOG_DEBUG("CURL", "size:%d,nitems:%d ",(int)size,(size_t)nitems);
////    EZLOG_DEBUG_GUESSLEN("HttpRequest_CURL", 1024*100, buffer);
//    return size*nitems;
}

int HttpRequest_CURL::s_progress_callback(void *clientp,double dltotal,double dlnow,double ultotal,double ulnow)
{

    HttpRequest_CURL *cthis = (HttpRequest_CURL*)clientp;
    return cthis->progress_callback(dltotal, dlnow, ultotal, ulnow);
}
int HttpRequest_CURL::progress_callback(double dltotal,double dlnow,double ultotal,double ulnow)
{
//    EZLOG_DEBUG("CURL", "dltotal:%d,dlnow:%d  ultotal:%d  ulnow:%d",(int)dltotal,(int)dlnow,(int)ultotal,(int)ulnow);
    return 0;
}


